package org.nightstudio.common.source.spi;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.nightstudio.common.util.exception.sys.DataBaseOperationException;
import org.nightstudio.common.util.exception.sys.NightStudioException;
import org.nightstudio.common.util.exception.sys.SystemInternalException;
import org.springframework.beans.factory.annotation.Autowired;

import com.cypheredge.osf.dao.ibatis.CommonQueryDaoIbatis;
import com.ibatis.sqlmap.client.SqlMapClient;

public abstract class AbsNightStudioDao<T> extends NightStudioHibernateDaoSupport<T> {
	private static Logger logger = Logger.getLogger(AbsNightStudioDao.class);
	@Autowired
	protected CommonQueryDaoIbatis commonQueryDao;
	private SqlMapClient sqlMapClient = null;
	private Object lockObj = new Object();

	public void setCommonQueryDao(CommonQueryDaoIbatis dao) {
		commonQueryDao = dao;
		synchronized (lockObj) {
			this.sqlMapClient = null;
		}
	}

	public CommonQueryDaoIbatis getCommonQueryDao() {
		return commonQueryDao;
	}

	protected SqlMapClient getSqlMapClient() {
		if (sqlMapClient == null) {
			synchronized (lockObj) {
				if (sqlMapClient == null) {
					sqlMapClient = this.getCommonQueryDao().getSqlMapClient();
				}
			}
		}
		return sqlMapClient;
	}

	protected void save(String tableName, Map<String, Object> map)
			throws NightStudioException {
		Set<String> columns = map.keySet();
		Object[] parameters = new Object[columns.size()];
		int i = 0;
		for (String column : columns) {
			parameters[i] = map.get(column);
			i++;
		}
		StringBuilder columnBuilder = new StringBuilder(100);
		StringBuilder questionBuilder = new StringBuilder(100);

		for (String column : columns) {
			columnBuilder.append(column).append(",");
			questionBuilder.append("?,");
		}
		String cols = "";
		String question = "";
		if (columnBuilder.length() > 0) {
			cols = columnBuilder.substring(0, columnBuilder.length() - 1);
		}
		if (questionBuilder.length() > 0) {
			question = questionBuilder.substring(0,
					questionBuilder.length() - 1);
		}

		String sql = new StringBuilder(100).append("insert into ").append(
				tableName).append(" (").append(cols).append(") ").append(
				"values (").append(question).append(")").toString();
		try {
			PreparedStatement stat = this.getSession().connection()
					.prepareStatement(sql);
			int pos = 1;
			for (Object parameter : parameters) {
				stat.setObject(pos, parameter);
				pos++;
			}
			stat.executeUpdate();
		} catch (Throwable e) {
			throw handleThrowable(e);
		}
	}
	
	protected void checkTable(Calendar c) throws NightStudioException {
		if (!this.tableExist(c)) {
			this.createTable(c);
		}
	}
	
	protected boolean tableExist(Calendar c) throws NightStudioException {
		return this.tableExist(this.getTableName(c));
	}
	
	protected boolean tableExist(String tableName) throws NightStudioException {
		try {
			Map<String, Object> param = new HashMap<String, Object>(1);
			param.put("table", tableName);
			try {
				this.getSqlMapClient().queryForObject("commonTableExist", param);
			} catch (SQLException e) {
				return false;
			}
			return true;
		} catch (Throwable e) {
			throw handleThrowable(e);
		}
	}
	
	protected void createTable(Calendar c) throws NightStudioException {
		Map<String, Object> param = new HashMap<String, Object>(2);
		param.put("his_table", this.getTableName(c));
		param.put("table", this.getTableName());
		try {
			this.getSqlMapClient().insert("commonCreateHisTable", param);
		} catch (SQLException e) {
			logger.error("", e);
			throw new DataBaseOperationException();
		}
	}
	
	protected String getTableName(Calendar c) throws NightStudioException {
		Calendar now = Calendar.getInstance();
		if (c.get(Calendar.YEAR) != now.get(Calendar.YEAR)
				|| c.get(Calendar.MONTH) != now.get(Calendar.MONTH)) {
			String year = String.valueOf(c.get(Calendar.YEAR));
			String month = String.valueOf(c.get(Calendar.MONTH) + 1);
			if (month.length() < 2) {
				month = "0" + month;
			}
			return getTableName() + "_" + year + month;
		} else {
			return getTableName();
		}
	}

	protected String getTableName() throws NightStudioException {
		try {
			return this.getTable().getName();
		} catch (IllegalArgumentException e) {
			logger.error("", e);
			throw new SystemInternalException();
		}
	}
}
